<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>瀑布流图片展示</title>
<style type="text/css">
*{margin:0;padding:0;list-style-type:none;}
a,img{border:0;}
#box{margin: 0 auto;position: relative;}
.item {box-shadow: 2px 2px 2px #999;position: absolute;}
</style>
</head>
<body>
<div id="box">
    <div class="item"><img src="images/01.jpg"></div>
    <div class="item"><img src="images/02.jpg"></div>
    <div class="item"><img src="images/03.jpg"></div>
    <div class="item"><img src="images/04.jpg"></div>
    <div class="item"><img src="images/05.jpg"></div>
    <div class="item"><img src="images/06.jpg"></div>
    <div class="item"><img src="images/07.jpg"></div>
    <div class="item"><img src="images/08.jpg"></div>
    <div class="item"><img src="images/09.jpg"></div>
    <div class="item"><img src="images/10.jpg"></div>
    <div class="item"><img src="images/11.jpg"></div>
    <div class="item"><img src="images/12.jpg"></div>
    <div class="item"><img src="images/13.jpg"></div>
    <div class="item"><img src="images/14.jpg"></div>
    <div class="item"><img src="images/15.jpg"></div>
    <div class="item"><img src="images/16.jpg"></div>
    <div class="item"><img src="images/17.jpg"></div>
</div>
<script>
// 代码执行到这里的时候DOM元素是加载好了，但是图片可能没加载完，有可能获取不了正确的图片尺寸
// 所以还是写上window.onload
window.onload = function () {
  const box = document.querySelector('#box')
  // 转成数组，方便后面的新图片push进来
  const items = Array.from(document.querySelectorAll('.item'))
  const gap = 10 // 固定图片之间间隙10px
  const width = items[0].offsetWidth
  var arr = [] // 记录每一列的高度
  var start = 0

  // 计算一行能放得下多少列
  var cols = Math.floor(window.innerWidth / (width + gap))
  // 给box计算宽度
  box.style.width = cols * (width + gap) - gap + 'px'
  waterfall()
  function waterfall () {
    // 如果瀑布流是从头开始的话，arr要清空
    if (start === 0) arr = []
    for (var i = start; i < items.length; i++) {
      if (i < cols) {
        // 第一行，从左往右
        items[i].style.left = i * (width + gap) + 'px'
        items[i].style.top = gap + 'px'
        // 每铺一张图都记录当前列的高度：当前图片高+ 2*gap（上下各一个）
        arr[i] = items[i].offsetHeight + 2 * gap
      } else {
        // 最短
        // var minIndex = 0 // 先假设第0个最小
        // for (var j = 1; j < arr.length; j++) {
        //   if (arr[j] < arr[minIndex]) {
        //     minIndex = j
        //   }
        // }
        // var minHeight = arr[minIndex]

        var minHeight = Math.min(...arr)
        var minIndex = arr.indexOf(minHeight)
        items[i].style.left = minIndex * (width + gap) + 'px'
        items[i].style.top = minHeight + 'px'
        // 铺完一张图之后当前arr的高度需要更新，为下一张图做准备
        // 把当前这一列（minIndex）的arr加上当前这张图高度以及一个间隙
        arr[minIndex] += items[i].offsetHeight + gap
      }
    }
  }
  
  window.onscroll = function () {
    var scrollTop = document.documentElement.scrollTop || document.body.scrollTop
    // 获取最高列，不包含后面家的那个间隙
    var maxHeight = Math.max(...arr) - gap
    // 在某些浏览器里scrollTop会得到小数，有可能并不能刚好相等
    if (scrollTop >= maxHeight - window.innerHeight - 10) {
      // 距离底部有10像素的时候开始触发到底，但是会频繁触发多次，使用节流
      // 只让最后一次生效
      // 在100ms以内再次触发到底行为，那就把上一次的定时器清除
      // 只有最后一次超过100ms才会触发行为
      clearTimeout(box.timer)
      box.timer = setTimeout(() => {
        console.log('到底了')
        // 要加载新的图片，下一次瀑布流从新的图片开始，起始点是当前length（现在把0~length-1坐标已经算好了）
        start = items.length
        // 向后端请求新的图片来渲染瀑布流
        // 用定时器模拟一下一秒之后从后端拿到数据了
        setTimeout(() => {
          var json = [
            "images/01.jpg",
            "images/02.jpg",
            "images/03.jpg",
            "images/04.jpg",
            "images/05.jpg",
            "images/06.jpg",
            "images/07.jpg",
            "images/08.jpg",
            "images/09.jpg",
            "images/10.jpg",
            "images/11.jpg",
            "images/12.jpg",
            "images/13.jpg",
            "images/14.jpg",
            "images/15.jpg",
            "images/16.jpg",
            "images/17.jpg"
          ]
          var imgs = []
          json.forEach(src => {
            var item = document.createElement('div')
            item.className = 'item'
            item.innerHTML = `<img src="${src}">`
            box.appendChild(item)
            // 把新创建的item也添加到items里来
            items.push(item)
            // 把每一个创建的img push到imgs数组里来
            imgs.push(item.querySelector('img'))
          })
          // item加入box以后重新瀑布流
          // 这里虽然DOM元素都已经可以使用了，但是图片可能没加载完
          // imgs全部onload就可以waterfall
          var count = 0
          imgs.forEach(img => {
            img.onload = function () {
              count++
              if (count === json.length) {
                // 所有图片都加载完了
                waterfall()
              }
            }
          })
        }, 1000)
      }, 100)
    }
  }

  // 窗口大小发生改变的时候要重新瀑布流
  window.onresize = function () {
    // 列数重新算
    var cols1 = Math.floor(window.innerWidth / (width + gap))
    if (cols1 !== cols) {
      cols = cols1
      // 给box计算宽度
      box.style.width = cols * (width + gap) - gap + 'px'
      // 整个从头开始
      start = 0
      waterfall()
    }
  }
}
</script>
</body>
</html>
